package com.my.study.design;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 通用的 Builder 模式构建器
 *
 * @author: yidujun
 * @create: 2021/04/07 19:06
 */
public class Builder<T> {

    private final Supplier<T> instantiator;
    private List<Consumer<T>> modifiers = new ArrayList<>();

    public Builder(Supplier<T> instantiator) {
        this.instantiator = instantiator;
    }

    public static <T> Builder<T> of (Supplier<T> instantiator) {
        return new Builder<>(instantiator);
    }

    public <P1> Builder<T> with(Consumer1<T, P1> consumer, P1 p1) {
        Consumer<T> c = instance -> consumer.accept(instance, p1);
        modifiers.add(c);
        return this;
    }

    public <P1, P2> Builder<T> with(Consumer2<T, P1, P2> consumer, P1 p1, P2 p2) {
        Consumer<T> c = instance -> consumer.accept(instance, p1, p2);
        modifiers.add(c);
        return this;
    }

    public <P1, P2, P3> Builder<T> with(Consumer3<T, P1, P2, P3> consumer, P1 p1, P2 p2, P3 p3) {
        Consumer<T> c = instance -> consumer.accept(instance, p1, p2, p3);
        modifiers.add(c);
        return this;
    }

    // 可以无限扩展...

    public T build() {
        T value = instantiator.get();
        modifiers.forEach(modifier -> modifier.accept(value));
        modifiers.clear();
        return value;
    }

    @FunctionalInterface
    public interface Consumer1<T, P1> {
        /**
         * Performs this operation on the given argument.
         *
         * @param t
         * @param p1
         */
        void accept(T t, P1 p1);
    }

    @FunctionalInterface
    public interface Consumer2<T, P1, P2> {
        /**
         * Performs this operation on the given argument.
         *
         * @param t
         * @param p1
         * @param p2
         */
        void accept(T t, P1 p1, P2 p2);
    }

    @FunctionalInterface
    public interface Consumer3<T, P1, P2, P3> {
        /**
         * Performs this operation on the given argument.
         *
         * @param t
         * @param p1
         * @param p2
         * @param p3
         */
        void accept(T t, P1 p1, P2 p2, P3 p3);
    }
}


class GirlFriend {
    private String name;
    private int age;
    private List<String> hobby;
    private Map<String, String> gift;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void addHobby(String hobby) {
        this.hobby = Optional.ofNullable(this.hobby).orElse(new ArrayList<>());
        this.hobby.add(hobby);
    }

    public void addGift(String day, String gift) {
        this.gift = Optional.ofNullable(this.gift).orElse(new HashMap<>());
        this.gift.put(day, gift);
    }

    public void setNameAndAge(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public List<String> getHobby() {
        return hobby;
    }

    public Map<String, String> getGift() {
        return gift;
    }

    @Override
    public String toString() {
        return "GirlFriend{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", hobby=" + hobby +
                ", gift=" + gift +
                '}';
    }
}

class MainTest {
    public static void main(String[] args) {
        GirlFriend girlFriend = Builder.of(GirlFriend::new)
                .with(GirlFriend::addHobby, "学习")
                .with(GirlFriend::addHobby, "旅游")
                .with(GirlFriend::addGift, "纪念日", "口号")
                .with(GirlFriend::setNameAndAge, "ws", 23)
                .build();

        System.out.println(girlFriend.toString());
    }
}
